package com.eastfair.questionnaire.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.utils.CollHelper;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.core.utils.StringUtils;
import com.eastfair.core.utils.ValidateUtil;
import com.eastfair.projectcore.api.ProjectCoreServiceFeign;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import com.eastfair.questionnaire.dao.QuestionMapper;
import com.eastfair.questionnaire.dto.QuestionDTO;
import com.eastfair.questionnaire.entity.Question;
import com.eastfair.questionnaire.entity.Questionnaire;
import com.eastfair.questionnaire.service.AnswerService;
import com.eastfair.questionnaire.service.QuestionService;
import com.eastfair.questionnaire.vo.AnswerVO;
import com.eastfair.questionnaire.vo.QuestionVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 问题
 * </p>
 *
 * @author yuwx
 * @date 2021-08-18
 */
@Slf4j
@Service
public class QuestionServiceImpl extends SuperServiceImpl<QuestionMapper, Question> implements QuestionService {
    private ProjectCoreServiceFeign projectCoreServiceFeign;
    private AnswerService answerService;

    @Autowired
    public QuestionServiceImpl(ProjectCoreServiceFeign projectCoreServiceFeign, AnswerService answerService) {
        this.projectCoreServiceFeign = projectCoreServiceFeign;
        this.answerService = answerService;
    }

    /**************sharding 分库分表操作 *****************/
    @Override
    public boolean updateByIdOfShard(Question entity) {
        UpdateWrapper<Question> updateWrapper = new UpdateWrapper<>();
        //可将指定字段更新为null
        updateWrapper.lambda().eq(Question::getProjectId, entity.getProjectId()).eq(Question::getId, entity.getId())
                .eq(Question::getIsEnable, BusinessConstant.YES)
                .eq(Question::getIsDelete, BusinessConstant.NO);
        entity.setProjectId(null);
        return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
    }

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(Question model) {
        //雪花ID
        if (Objects.isNull(model.getId())) {
            model.setId(DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId()));
        }
        model.setProjectId(ContextUtil.getProjectId());
        return R.successDef();
    }

    @Override
    public List<QuestionVO> list(Long projectId, Long questionnaireId) {
        if (Objects.isNull(projectId) || Objects.isNull(questionnaireId)) {
            throw new NullPointerException();
        }
        QueryWrapper<Question> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(Question::getProjectId, projectId).eq(Question::getQuestionnaireId, questionnaireId)
                .eq(Question::getIsEnable, BusinessConstant.YES)
                .eq(Question::getIsDelete, BusinessConstant.NO)
                .orderByAsc(Question::getSequence);
        List<Question> questionList = list(queryWrapper);
        return ConvertUtil.convertList(questionList, QuestionVO.class);
    }

    @Override
    public List<QuestionVO> listWithAnswer(Long projectId, Long questionnaireId) {
        if (Objects.isNull(projectId) || Objects.isNull(questionnaireId)) {
            throw new NullPointerException();
        }
        List<QuestionVO> questionList = list(projectId, questionnaireId);
        if (CollectionUtil.isEmpty(questionList)) {
            return Collections.emptyList();
        }
        questionList.parallelStream().forEach(question -> setAnswerList(question));
        return questionList;
    }

    @Override
    public List<QuestionVO> listWithAnswer(Long projectId, Long questionnaireId, String subjectType, Long subjectId) {
        if (Objects.isNull(projectId) || Objects.isNull(questionnaireId)) {
            return Collections.emptyList();
        }
        List<QuestionVO> questionList = list(projectId, questionnaireId);
        questionList.stream().forEach(question -> {
            setAnswerList(question, subjectType, subjectId);
        });
        return questionList;
    }

    @Override
    public List<QuestionVO> listWithSelectedAnswer(Long projectId, Long questionnaireId, String subjectType, Long subjectId) {
        if (Objects.isNull(projectId) || Objects.isNull(questionnaireId)
                || Objects.isNull(subjectId) || StringUtils.isBlank(subjectType)) {
            throw new NullPointerException();
        }
        List<QuestionVO> questionList = list(projectId, questionnaireId);
        if (CollectionUtil.isEmpty(questionList)) {
            return Collections.emptyList();
        }
        List<Long> questionIdList = questionList.stream().map(QuestionVO::getId).collect(Collectors.toList());
        List<AnswerVO> answerSelectedList = answerService.listSelected(projectId, questionIdList, subjectType, subjectId);
        return setAnswerList(questionList, answerSelectedList).stream().filter(questionVO -> !CollectionUtil.isEmpty(questionVO.getAnswerList())).collect(Collectors.toList());
    }

    @Override
    public QuestionVO get(Long projectId, Long id) {
        if (Objects.isNull(id)) {
            return null;
        }
        QueryWrapper<Question> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(Question::getId, id)
                .orderByAsc(Question::getSequence);
        Question question = getOne(queryWrapper);
        return BeanUtil.toBean(question, QuestionVO.class);
    }

    @Override
    public QuestionVO save(QuestionDTO questionDTO) {
        if (Objects.isNull(questionDTO)) {
            throw new NullPointerException("questionDTO is null");
        }
        if (!ValidateUtil.validateSimple(questionDTO, QuestionDTO.validateBase.class, QuestionDTO.validateSave.class)) {
            throw new IllegalArgumentException("params is error");
        }
        Question question = BeanUtil.toBean(questionDTO, Question.class);
        if (Objects.isNull(questionDTO.getId())) {
            save(question);
        } else {
            updateByIdOfShard(question);
        }
        return BeanUtil.toBean(question, QuestionVO.class);
    }

    @Override
    @Transactional
    public void delete(Long projectId, Long id) {
        Question question = Question.builder().projectId(projectId).id(id).isDelete(BusinessConstant.YES).build();
        updateByIdOfShard(question);
        answerService.deleteByQuestion(projectId, id);
    }

    @Override
    @Transactional
    public void deleteByQuestionnaire(Long projectId, Long questionnaireId) {
        List<QuestionVO> questionList = list(projectId, questionnaireId);
        UpdateWrapper<Question> updateWrapper = new UpdateWrapper<>();
        //可将指定字段更新为null
        updateWrapper.lambda().eq(Question::getProjectId, projectId).eq(Question::getQuestionnaireId, questionnaireId);
        Question question = Question.builder().isDelete(BusinessConstant.YES).build();
        SqlHelper.retBool(this.getBaseMapper().update(question, updateWrapper));
        questionList.stream().forEach(questionVO -> answerService.deleteByQuestion(projectId, questionVO.getId()));
    }

    /**
     * Description 为问题设置答案，
     *
     * @param questionVO
     * @return void
     * @Date 16:58 2021/8/25
     * @Author yuwx
     **/
    private void setAnswerList(QuestionVO questionVO) {
        List<AnswerVO> answerList = answerService.listByLevel(questionVO.getProjectId(), questionVO.getId());
        if (CollectionUtil.isEmpty(answerList)) {
            answerList = Collections.emptyList();
        }
        questionVO.setAnswerList(answerList);
    }

    /**
     * Description 为问题设置答案，以及答题结果
     *
     * @param questionVO
     * @param subjectType
     * @param subjectId
     * @return void
     * @Date 17:00 2021/8/25
     * @Author yuwx
     **/
    private void setAnswerList(QuestionVO questionVO, String subjectType, Long subjectId) {
        List<AnswerVO> answerList = answerService.listByLevel(questionVO.getProjectId(), questionVO.getId(), subjectType, subjectId);
        if (CollectionUtil.isEmpty(answerList)) {
            answerList = Collections.emptyList();
        }
        questionVO.setAnswerList(answerList);
    }

    /**
     * Description 拼装答案到问题上
     *
     * @param questionList
     * @param answerSelectedList
     * @return java.util.List<com.eastfair.questionnaire.vo.QuestionVO>
     * @Date 13:08 2021/9/15
     * @Author yuwx
     **/
    private List<QuestionVO> setAnswerList(List<QuestionVO> questionList, List<AnswerVO> answerSelectedList) {
        if (CollectionUtil.isEmpty(questionList)) {
            return Collections.emptyList();
        }
        if (CollectionUtil.isEmpty(answerSelectedList)) {
            return questionList;
        }
        Map<Long, List<AnswerVO>> answerGroupMap = answerSelectedList.stream().collect(Collectors.groupingBy(AnswerVO::getQuestionId));
        return questionList.stream().peek(questionVO -> questionVO.setAnswerList(answerGroupMap.get(questionVO.getId()))).collect(Collectors.toList());
    }

    @Override
    public Map<Serializable, Object> findNameByIds(Set<Serializable> set) {
        return null;
    }

    @Override
    public Map<Serializable, Object> findByIds(Set<Serializable> set) {
        List<QuestionVO> questionVOList = set.stream().map(id -> {
            return get(ContextUtil.getProjectId(), (Long) id);
        }).collect(Collectors.toList());
        return CollHelper.uniqueIndex(questionVOList, QuestionVO::getId, QuestionVO::getName);
    }
}
